'''
Created on Oct 6, 2013

@author: Gabriel
'''
import urllib2
import bs4
import subprocess
import re
import os
import persistence
import shutil
import time
import uTorrent

class SearchEngine(object):
    MAGNET_LINK = 'magnetLink'
    TORRENT_NAME = 'name'

    COMMON_WORD_SEPARATORS = '[_\s\.\-]*'

    ENGINE1 = "http://thepiratebay.sx/search/";

    def findMatchingSearchResult(self, htmlContent, query):
        searchResultMagnetLink = {}
        try:
            mainSearchDom = bs4.BeautifulSoup(htmlContent)
            searhResultsTable = mainSearchDom.find(id = u'searchResult')
            if searhResultsTable :
                for row in searhResultsTable.findAll('tr') :
                    # If needed to validate the search results, here is the title of the 1st one
                    searchResultTitleTag = row.find(u'a', class_ = u'detLink')
                    if searchResultTitleTag :
                        perfectMatch = re.match(query.replace(' ', self.COMMON_WORD_SEPARATORS), searchResultTitleTag.string, re.I)
                        if perfectMatch :
                            searchResultMagnetLink[SearchEngine.TORRENT_NAME] = searchResultTitleTag.string
                            # print searchResultMagnetLink['name']
                            # Get the first magnet link in the search results
                            searchResultMagnetLinkTag = row.find(u'a', title = u'Download this torrent using magnet')
                            searchResultMagnetLink[SearchEngine.MAGNET_LINK] = searchResultMagnetLinkTag[u'href']
                            print "Found match for download:" + searchResultMagnetLink
                            break
            else :
                # print 'No results matching the search'
                pass
        except :
            print "Error parsing search results."
        return searchResultMagnetLink

    def search(self, query):
        url = self.ENGINE1 + urllib2.quote(query.lower())
        # print url
        mainSearchHtml = self.getUrl(url)
        #  print mainSearchHtml
        searchResult = self.findMatchingSearchResult(mainSearchHtml, query.lower())
        return searchResult

    def getUrl(self, url):
        req = urllib2.Request(url)
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0')
        response = urllib2.urlopen(req)
        data = response.read()
        response.close()
        return data


class TixatiProvider(object):

    # Constants
    UNFINISHED_DOWNLOAD_DIR = "C:/tmp/downloads"
    COMPLETED_DOWNLOAD_DIR = "C:/tmp/completed"

#    COMMAND = '/usr/bin/tixati -starthiddenintray "%s"'
    COMMAND = '"c:\\Program Files\\tixati\\tixati.exe" -starthiddenintray "%s"'

    def addDownload(self, magnetLink):
        print self.COMMAND % str(magnetLink.replace('"', ''))
        subprocess.call(self.COMMAND % str(magnetLink).replace('"', ''))

    def isDownloadComplete(self, trackingInfo):
        entries = os.listdir(self.UNFINISHED_DOWNLOAD_DIR)
        for entry in entries :
            if trackingInfo["fileName"] == entry :
                print "Found completed download: " + entry

        # List the files and folders of the completed downloads folder
        # If the file is in the tracked files, move it to destination folder
        pass


class UTorrentProvider(object):
    # Constants
    PROVIDER_ID = "uTorrentProvider"
    VIDEO_EXTENSIONS_PATTERN = ".*(\.mkv$|\.avi$|\.mpg$|\.mp4$|\.ts$)"

    # Attributes
    _uTorrentClient = uTorrent.uTorrent()

    def __init__(self):
        print(self._uTorrentClient.webui_ls())

    def addDownload(self, magnetLink):
        trackingInfo = None
        self._uTorrentClient.webui_add_url(magnetLink)
        downloadId = self.__getHashFromMagnetLink(magnetLink)
        downloadList = self._uTorrentClient.webui_ls()
        for download in downloadList :
            if downloadId.lower() == download[uTorrent.Constants.UT_TORRENT_DETAIL_HASH].lower():
                print "Download successfully added to uTorrent"
                trackingInfo = {"provider":self.PROVIDER_ID, "uTorrentId":downloadId, "magnetLink":magnetLink}
                break
        return trackingInfo


    def isDownloadInProgress(self, trackingInfo):
        inProgress = False
        downloadList = self._uTorrentClient.webui_ls()
        for download in downloadList :
            if trackingInfo['uTorrentId'].lower() == download[uTorrent.Constants.UT_TORRENT_PROP_HASH].lower():
                inProgress = True
                break
        return inProgress

    def isDownloadComplete(self, trackingInfo):
        complete = False
        downloadList = self._uTorrentClient.webui_ls()
        for download in downloadList :
            if trackingInfo['uTorrentId'].lower() == download[uTorrent.Constants.UT_TORRENT_PROP_HASH].lower():
                if download[uTorrent.Constants.UT_TORRENT_STAT_P1000_DONE] == 1000:
                    complete = True
                break
        return complete

    def getDownloadedFile(self, trackingInfo):
        downloadedFile = None
        downloadList = self._uTorrentClient.webui_ls()
        for download in downloadList :
            if trackingInfo['uTorrentId'].lower() == download[uTorrent.Constants.UT_TORRENT_PROP_HASH].lower():
                downloadDir = download[uTorrent.Constants.UT_TORRENT_DETAIL_DOWNLOAD_DIR]
                downloadedFilesList = self._uTorrentClient.webui_ls_files(trackingInfo['uTorrentId'])
                for downloadedFile in downloadedFilesList['files'][1]:
                    fileName = downloadedFile[uTorrent.Constants.UT_FILE_NAME]
                    # Supports only 1 video file per torrent
                    if self.__isVideoFile(fileName):
                        downloadedFile = {"dir":downloadDir, "file":fileName, 'extension': self.__getVideoFileExtension(fileName)}
                        break
                break
        return downloadedFile


    def stopDownload(self, trackingInfo):
        self._uTorrentClient.webui_stop_torrent(trackingInfo['uTorrentId'])


    def deleteDownload(self, trackingInfo):
        self._uTorrentClient.webui_remove(trackingInfo['uTorrentId'])


    def __isVideoFile(self, path):
        return re.match(self.VIDEO_EXTENSIONS_PATTERN, path, re.IGNORECASE)

    def __getVideoFileExtension(self, path):
        return re.match(self.VIDEO_EXTENSIONS_PATTERN, path, re.IGNORECASE).group(1)


    def __getHashFromMagnetLink(self, magnetLink):
        return re.match(".*urn:btih:([^&]*)&.*", magnetLink).group(1)


class TorrentDownloadMgr(persistence._Persistent):
    # Constants
    VIDEOS_LIBRARY_BASE_DIR = "c:/tmp/videos/"

    # Attributes
    _provider = UTorrentProvider()
    _search = SearchEngine()

    def __init__(self):
        super(TorrentDownloadMgr, self).__init__("TorrentDownloadMgr", "dataObject", [])


    #
    # Requests a new download from the provider and add it to tracking list
    #
    def trackDownload(self, showName, destinationFileName, torrentSearchResult):
        success = False
        alreadyTracking = False
        for download in self._DATA_OBJECT :
            if download['name'] == showName :
                print "Serie being tracked, checking status with provider"
                if self._provider.isDownloadInProgress(download['trackingInfo']):
                    alreadyTracking = True
                else :
                    self._DATA_OBJECT.remove(download)

        if not alreadyTracking :
            print "Adding download for: " + showName
            trackingInfo = self._provider.addDownload(torrentSearchResult[SearchEngine.MAGNET_LINK])
            if trackingInfo :
                self._DATA_OBJECT.append({"name":showName, "fileName":destinationFileName, "trackingInfo":trackingInfo})
                self._save()
                success = True
            else :
                print "Failed to add download for: " + showName
        else :
            print "Serie already being downloaded: " + showName
            success = True
        return success

    #
    # Check for all monitored downloads and move it to the library folder.
    #
    def monitorDownloads(self):
        for download in self._DATA_OBJECT :
            if self._provider.isDownloadComplete(download['trackingInfo']):
                print "Download is complete: " + download["name"]
                self._provider.stopDownload(download['trackingInfo'])
                fileName = self._provider.getDownloadedFile(download['trackingInfo'])
                if fileName :
                    destDir = self.VIDEOS_LIBRARY_BASE_DIR + download['name']
                    if not os.path.exists(destDir):
                        os.makedirs(destDir)
                    shutil.move(os.path.join(fileName["dir"], fileName["file"]), destDir + "/" + download["fileName"] + fileName['extension'])
                self._provider.deleteDownload(download['trackingInfo'])
                self._DATA_OBJECT.remove(download)


    def downloadNewEpisode(self, showName, lastSeason, lastEpisode):
        result = False
        # Search episode by incrementing episode number
        newEpisode = 'S%02dE%02d' % (lastSeason, lastEpisode + 1)
        magnetLink = self._search.search(showName + ' ' + newEpisode)
        if SearchEngine.MAGNET_LINK not in magnetLink :
            # Search episode by incrementing season number
            newEpisode = 'S%02dE%02d' % (lastSeason + 1, 1)
            magnetLink = self._search.search(showName + ' ' + newEpisode)
        # If any found, download it
        if SearchEngine.MAGNET_LINK in magnetLink :
            result = self.trackDownload(showName, showName + ' ' + newEpisode, magnetLink)
        return result



def mainFlow():
    databaseMgr = persistence.DatabaseMgr()
    databaseMgr.download('http://192.168.1.2:8088/Development/videosDatabase.json')

    downloadMgr = TorrentDownloadMgr()

    # Downloader flow:
    #
    # For each series
    for showName in databaseMgr.listShowNames():
    #   Find the last episode present
        lastEpisodeAndSeason = databaseMgr.getLastEpisodeAndSeason(showName)

    #   Search for the next episode by incrementing episode number
        if lastEpisodeAndSeason :
            downloadAdded = downloadMgr.downloadNewEpisode(showName, lastEpisodeAndSeason['season'], lastEpisodeAndSeason['episode'])

    while True:
        print "Monitoring downloads..."
        time.sleep(10)
    # For each tracked download
    #   Check completed downloads folder for completion
    #   If completed, request download provider to stop (torrent removal) and move the file to its final destination
        downloadMgr.monitorDownloads()


if __name__ == '__main__':
    mainFlow()
#     perfectMatch = re.match("big bang theory s03e02".replace(' ', SearchEngine.COMMON_WORD_SEPARATORS), "The Big Bang Theory S03E02 HDTV XviD-XII [eztv]", re.I)
#     print perfectMatch

